﻿namespace FolderSync
{
    using System;
    using System.Text;
    using System.Linq;
    using System.Collections.Generic;
    using System.Threading;

    class ConsoleNotifier : INotifier
    {
        struct NotifierMessage
        {
            public NotifierLevel level;
            public string header;
            public string message;
        }; public bool ToConsole { get; set; }

        public System.IO.FileInfo LogFile { get; set; }
        public NotifierLevel Level { get; set; }
        public string LogTag;
        private Queue<NotifierMessage> MsgQueue = new Queue<NotifierMessage>();
        private Thread writerThread;

        public void Write(bool isDated, NotifierLevel MessageLevel, string format
            , object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            var s = string.Format(format, p0, p1, p2, p3, p4);

            string lineHeader =
                isDated
                ? string.Format("{0} |{1}{2}: ", DateTime.Now.ToString("yyyyMMdd HHmmss.ff"), MessageLevel, LogTag)
                : string.Format("{0}{1}: ", Level, LogTag)
                ;
            lock (MsgQueue)
            {
                MsgQueue.Enqueue(new NotifierMessage() { level = MessageLevel, header = lineHeader, message = s, });
            }
            Writer();
            //if (writerThread == null || !writerThread.IsAlive)
            //{
            //    writerThread = new Thread(this.Writer);
            //    writerThread.Name = "LogWriter";
            //    writerThread.Start();
            //}
        }
        public void Writer()
        {
            IEnumerable<NotifierMessage> msgs;
            while (MsgQueue.Count() != 0)
            {
                lock (MsgQueue)
                {
                    msgs = MsgQueue.ToArray();
                    MsgQueue.Clear();
                }
                foreach (var msg in msgs)
                {
                    if (LogFile != null)
                        lock (LogFile)
                        {
                            var writer = LogFile.AppendText();
                            writer.Write(msg.header);
                            writer.WriteLine(msg.message);
                            writer.Close();
                        }
                    if (ToConsole
                        && msg.level <= Level) 
                    {
                        lock (Console.Out)
                        {
                            Console.BackgroundColor = ConsoleColor.Black;
                            Console.ForegroundColor = ConsoleColor.DarkGray;
                            Console.Error.Write(msg.header);
                            switch (msg.level)
                            {
                                case NotifierLevel.Error:
                                    Console.BackgroundColor = ConsoleColor.Red;
                                    Console.ForegroundColor = ConsoleColor.White;
                                    break;
                                case NotifierLevel.Warning:
                                    Console.BackgroundColor = ConsoleColor.Yellow;
                                    Console.ForegroundColor = ConsoleColor.Black;
                                    break;
                                case NotifierLevel.Debug:
                                    Console.BackgroundColor = ConsoleColor.Black;
                                    Console.ForegroundColor = ConsoleColor.DarkGray;
                                    break;
                                default:
                                    Console.ResetColor();
                                    break;
                            }
                            Console.Out.Write(msg.message);
                            Console.ResetColor();
                            Console.Out.WriteLine();
                        }
                    }
                }
            }
        }

        public void Error(string format
            , object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            this.Write(true, NotifierLevel.Error, format, p0, p1, p2, p3, p4);
        }
        public void Warning(string format
            , object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            this.Write(true, NotifierLevel.Warning, format, p0, p1, p2, p3, p4);
        }
        public void Message(string format
            , object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            this.Write(true, NotifierLevel.Message, format, p0, p1, p2, p3, p4);
        }
        public void Message(NotifierLevel MessageLevel, string format, object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            this.Write(true, MessageLevel, format, p0, p1, p2, p3, p4);
        }
        public void Message(IEnumerable<string> lines)
        {
            lines.All(l => { this.Write(false, NotifierLevel.Message, l); return true; });
        }

        public void Debug(string format
            , object p0 = null, object p1 = null, object p2 = null, object p3 = null, object p4 = null)
        {
            this.Write(true, NotifierLevel.Debug, format, p0, p1, p2, p3, p4);
        }
    }
}
